/*
 * Famon (http://code.google.com/p/famon/)
 * Copyright (c) 2010 Carl Crous.
 *
 * This file is part of Famon.
 *
 * Famon is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Famon is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Famon.  If not, see <http://www.gnu.org/licenses/>.
 */

package za.org.foobar.famon.demo;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import za.org.foobar.famon.Serializer;
import za.org.foobar.famon.reporter.FamonFileBufferWorkProcessor;
import za.org.foobar.famon.reporter.FamonReporterLogic;
import za.org.foobar.famon.reporter.FamonReporterProperties;
import za.org.foobar.famon.reporter.FamonWorkProcessor;
import za.org.foobar.famon.util.Util;

import java.io.FileInputStream;
import java.io.IOException;

/**
 *
 */
public class Main {
    public static String getUser() {
        return "Any User";
    }
//TODO: InputStream is = getClass().getResourceAsStream( "/test.properties" );

    public static Log log = LogFactory.getLog(Main.class);

    public static void printUsage() {
        StringBuilder str = new StringBuilder();
        str.append("Usage: [options]\n")
            .append("Options: \n")
                .append("  -h: Print this usage\n")
                .append("  -p <properties file>: Load the give properties file\n")
                .append("  -l: Poll mode (for the file processor)\n")
                .append("  -f: Flush the buffered failures (for the file processor)\n")
                .append("  -s <file>: Send buffered messages in the given file\n")
                .append("  -r <n>: Perform the failures n times\n")
                ;
        log.info(str.toString());
    }

    private static String propertiesFile = "famon-reporter.properties";
    private static boolean poll = false;
    private static boolean flush = false;
    private static String sendFile = null;
    private static int repeatCount = 1;

    private static boolean handleArgs(String args[]) {
        int i = 0;
        while (i < args.length) {
            if (args[i].length() == 0) {
                continue;
            }
            if (args[i].charAt(0) == '-' && args[i].length() > 1) {
                String nextParam = args[i].length() > 2
                        ? args[i].substring(2).trim()
                        : args.length > i
                        ? args[i+1] : null;
                int useNextParam = args[i].length() > 2 ? 0 : 1;
                switch (args[i].charAt(1)) {
                    case 'h':
                        return false;
                    case 'p':
                        if (nextParam == null) {
                            log.info("Missing parameter for " + args[i]);
                            return false;
                        }
                        propertiesFile = nextParam;
                        i += useNextParam;
                        break;
                    case 'l':
                        poll = !poll;
                        break;
                    case 'f':
                        flush = !flush;
                        break;
                    case 's':
                        if (nextParam == null) {
                            log.info("Missing parameter for " + args[i]);
                            return false;
                        }
                        sendFile = nextParam;
                        i += useNextParam;
                        break;
                    case 'r':
                        if (nextParam == null) {
                            log.info("Missing parameter for " + args[i]);
                            return false;
                        }
                        repeatCount = Integer.parseInt(nextParam);
                        i += useNextParam;
                        break;
                    default:
                        log.info("Invalid argument \"" + args[i] + "\"");
                        return false;
                }
            } else {
                log.info("Invalid argument \"" + args[i] + "\"");
                return false;
            }
            i++;
        }
        return true;
    }

    public static void main(String args[]) throws IOException {
        if (!handleArgs(args)) {
            printUsage();
            return;
        }

        FamonReporterLogic logic = new FamonReporterLogic();
        FamonReporterProperties prop = new FamonReporterProperties();
        prop.loadProperties(logic, propertiesFile);
        // If we are given an argument, use it as an input file for a failure.
        FamonFileBufferWorkProcessor fileBufferProcessor = null;
        if (flush || poll) {
            FamonWorkProcessor workProcessor = logic.getWorkProcessor();
            if (!(workProcessor instanceof FamonFileBufferWorkProcessor)) {
                log.info("Cannot use -f with a processor other than the file buffer processor");
                return;
            }
            fileBufferProcessor = (FamonFileBufferWorkProcessor)workProcessor;
        }
        if (flush) {
            fileBufferProcessor.sendBufferedFailures();
            return;
        } else if (poll) {
            fileBufferProcessor.getPollingThread().start();
            return;
        } else if (sendFile != null) {
            log.info("Sending file " + sendFile + " as JSON to the server");
            try {
                String json = Util.readFileMapped(sendFile);
                logic.sendFailureBatch(Serializer.deserializeFailureBatch(json));
            } catch (IOException e) {
                log.error("Could not read file: " + sendFile, e);
                return;
            }
        }


        log.info("Going to cause an exception in a class which is ignored");
        try {
            Ignore.MakeError();
        } catch (Exception e) {
            log.info("Sending Ignored Failure message");
            logic.fail(e);
        }
        log.info("Going to cause an exception which is ignored");
        try {
            throw new IgnoredException("This exception should be ignored");
        } catch (IgnoredException e) {
            log.info("Sending Ignored Failure message");
            logic.fail(e);
        }
        log.info("Performing practical failure delivery demo.");
        log.info("This message is going to be displayed in the failure report");
        log.warn("Warning we are doing something weird");
        runFailureLoop(logic);
        log.info("Done failure - This should NOT be in the failure!");
    }

    public static void runFailureLoop(FamonReporterLogic logic) {
        for (int i = 0; i < repeatCount; i++) {
            runFailures(logic);
        }
    }

    public static void runFailures(FamonReporterLogic logic) {
        for (int i = 0; i < 4; i++) {
            try {
                doFailure(i);
            } catch (Throwable e) {
                log.info("Got an exception!?");
                logic.fail(e);
            }
        }
    }

    private static void doFailure(int i) throws Throwable {
        switch (i) {
            case 0:
                // File not found
                new FileInputStream("no-file-exists.txt");
                break;
            case 1:
                // Division by zero
                int j = 10 / (i-1);
                break;
            case 2:
                throw new RuntimeException("Custom exception");
            case 3:
                throw new Throwable("Throwable exception");
            default:
                throw new IllegalArgumentException("Invalid failure index " + i);
        }
    }

    public static class IgnoredException extends Exception {
        public IgnoredException(String message) {
            super(message);
        }
    }
}
